package two_xia.myPainter;


import two_xia.myPainter.shape.Shape;
import two_xia.myPainter.shape.*;
import two_xia.myPainter.utils.FileUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class DrawListener extends MouseAdapter implements ActionListener {
    String shape = "铅笔";    //初始化工具
    Color color = Color.BLACK;  //初始化颜色
    int stroke = 1; //默认画笔粗细为1,公开属性 ; StrokeChange直接修改
    private CustomColorPanel customColorPanel;
    private int x1, y1, x2, y2;
    private Graphics2D g;
    private JPanel drawingArea;
    private Shape nowShape;
    private int number = 0;// 记录数器，用来记录已经存储的图形个数。


    private ArrayList<Shape> shapeArray;
    private Stack<Shape> undoStack;

    public DrawListener(JPanel j, ArrayList<Shape> shapeArray, Stack<Shape> undoStack) {
        drawingArea = j;
        this.shapeArray = shapeArray;
        this.undoStack = undoStack;
    }

    public void setCustomColorPanel(CustomColorPanel customColorPanel) {
        this.customColorPanel = customColorPanel;
    }

    //获取颜色
    public void onColorChanged(Color color) {
        this.color = color;
        System.out.println("color = " + color);
    }

    //获取形状
    public void actionPerformed(ActionEvent e) {
        JButton button = (JButton) e.getSource();
        shape = button.getActionCommand();
        System.out.println("String = " + shape);
        if (shape.equals("保存")) {
            FileUtils.saveFile(drawingArea);
            //TODO:使用过操作之后,回归"铅笔"状态
            shape = "铅笔";
        } else if (shape.equals("撤销")) {
            //入撤销栈
            undoStack.push(shapeArray.get(shapeArray.size() - 1));
            //删除最上面的操作
            shapeArray.remove(shapeArray.size() - 1);
            drawingArea.repaint(); // 重绘画布
            shape = "铅笔";
        } else if (shape.equals("重做")) {
            //取出撤销栈顶的元素
            shapeArray.add(undoStack.pop());
            drawingArea.repaint(); // 重绘画布
            shape = "铅笔";
        } else if (shape.equals("打开")) {
            FileUtils.openFile(drawingArea);
        }
    }

    // 实现椭圆、矩形、直线,只需要监听两个操作：鼠标按下和鼠标抬起
    public void mousePressed(MouseEvent e) {
        //undoStack.clear();    //这一步没有逻辑将会混乱
        //System.out.println("清空undoStack");

        g = (Graphics2D) drawingArea.getGraphics();
        g.setColor(color);
        g.setStroke(new BasicStroke(stroke));
        x1 = e.getX();
        y1 = e.getY();
    }

    //和mousePressed不同,mouseClicked对应鼠标按下并且立即松开的情况
    @Override
    public void mouseClicked(MouseEvent e) {
        if (shape.equals("填充")) {
            floodFill(x1, y1, drawingArea);
        } else if (shape.equals("取色")) {
            getColorAtPixel();
            customColorPanel.Synchronous(color);
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        //  x2, y2已在mouseDragged获取
        switch (shape) {
            case "直线": {
                nowShape = new ShapeLine(x1, y1, x2, y2, color, new BasicStroke(stroke));
                nowShape.draw(g);

                // 将图形对象存入到数组中
                shapeArray.add(nowShape);
                number++;
                break;
            }
            case "矩形": {
                nowShape = new ShapeRect(Math.min(x1, x2), Math.min(y1, y2),
                        Math.abs(x1 - x2), Math.abs(y1 - y2), color,
                        new BasicStroke(stroke));
                nowShape.draw(g);

                // 将图形对象存入到数组中
                shapeArray.add(nowShape);
                number++;
                break;

            }
            case "椭圆": {
                nowShape = new ShapeOval(x1, y1, Math.abs(x2 - x1), Math.abs(y2 - y1), color,
                        new BasicStroke(stroke));
                nowShape.draw(g);

                // 将图形对象存入到数组中
                shapeArray.add(nowShape);
                number++;
                break;

            }
            case "三角形": {
                nowShape = new ShapeTriangle(x1, y1, x2, y2,
                        color, new BasicStroke(stroke));
                nowShape.draw(g);

                // 将图形对象存入到数组中
                shapeArray.add(nowShape);
                number++;
                break;

            }
        }
    }

    //铅笔功能需要监听鼠标拖动的操作
    public void mouseDragged(MouseEvent e) {
        x2 = e.getX();
        y2 = e.getY();
        if (shape.equals("铅笔")) {
            // 根据数据来实例化图形对象
            nowShape = new ShapeLine(x1, y1, x2, y2, color, new BasicStroke(stroke));
            // 调用图形的绘图方法
            nowShape.draw(g);

            // 将图形对象存入到数组中
            shapeArray.add(nowShape);
            number++;

            x1 = x2;
            y1 = y2;
        } else if (shape.equals("橡皮擦")) {
            nowShape = new ShapeEraser(x1, y1, x2, y2, drawingArea.getBackground(), new BasicStroke(stroke));
            nowShape.draw(g);

            // 将图形对象存入到数组中
            shapeArray.add(nowShape);
            number++;

            x1 = x2;
            y1 = y2;
        }
    }

    // 油漆桶算法实现
    private void floodFill(int x, int y, Component drawingArea) {
        BufferedImage image = new BufferedImage(drawingArea.getWidth(), drawingArea.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        drawingArea.paint(g2d);
        g2d.dispose();

        // 获取绘图区域的颜色数组
        int width = drawingArea.getWidth();
        int height = drawingArea.getHeight();
        int[] pixels = new int[width * height];
        PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            System.err.println("Interrupted waiting for pixels");
            return;
        }
        // 创建一个标记数组，用于记录某个像素是否已经被访问过
        boolean[] marked = new boolean[width * height];

        // 获取目标颜色
        int targetColor = pixels[y * width + x];

        // 检查起始点的颜色，如果与目标颜色相同，则不需要填充
        if (targetColor == color.getRGB()) {
            return;
        }

        // 递归填充
        fill(x, y, width, height, pixels, targetColor, color.getRGB(), drawingArea.getGraphics());
    }

    public void fill(int x, int y, int width, int height, int[] pixels, int targetColor, int fillColor, Graphics g) {
        if (targetColor == fillColor) return;

        boolean[] marked = new boolean[width * height];
        Queue<Point> queue = new LinkedList<>();
        queue.offer(new Point(x, y));

        while (!queue.isEmpty()) {
            Point point = queue.poll();
            x = point.x;
            y = point.y;

            if (x < 0 || x >= width || y < 0 || y >= height || pixels[y * width + x] != targetColor || marked[y * width + x]) {
                continue;
            }

            g.setColor(color);
            g.fillRect(x, y, 1, 1);
            pixels[y * width + x] = fillColor;
            marked[y * width + x] = true;

            queue.offer(new Point(x + 1, y));
            queue.offer(new Point(x - 1, y));
            queue.offer(new Point(x, y + 1));
            queue.offer(new Point(x, y - 1));
        }
    }


    //    颜色汲取器
    private void getColorAtPixel() {
        // Robot 可以模拟鼠标和键盘的输入。基于给定屏幕设备创建一个Robot
        Robot robot = null;
        try {
            robot = new Robot();
            // 获取鼠标在屏幕中移动的坐标位置
            Point mousePoint = MouseInfo.getPointerInfo().getLocation();
            // 获取鼠标所在位置的X值
            int X = mousePoint.x;
            // 获取鼠标所在位置的Y值
            int Y = mousePoint.y;
            // 获取指定屏幕坐标处的像素颜色
            Color pixelColor = robot.getPixelColor(X, Y);
            System.out.println(pixelColor.toString());
            color = pixelColor;
        } catch (AWTException e) {
            throw new RuntimeException(e);
        }
    }

    private void executeCommand(Shape command) {
        command.draw(g);
        shapeArray.add(command);
    }

}